package org.dromara.system.service.impl;

import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.constants.OrderConstants;
import org.dromara.system.domain.*;
import org.dromara.system.domain.vo.PayAppClientVo;
import org.dromara.system.mapper.SysUserMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.dromara.system.domain.bo.PayAppBo;
import org.dromara.system.domain.vo.PayAppVo;
import org.dromara.system.mapper.PayAppMapper;
import org.dromara.system.service.IPayAppService;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 应用列表Service业务层处理
 *
 * @author Gavino
 * @date 2024-10-22
 */
@RefreshScope
@RequiredArgsConstructor
@Service
public class PayAppServiceImpl implements IPayAppService {

    private final PayAppMapper baseMapper;
    private final SysUserMapper sysUserMapper;
    @Value("${gatewayDomain}")
    public String gatewayDomain;

    /**
     * 查询应用列表
     *
     * @param appId 主键
     * @return 应用列表
     */
    @Override
    public PayAppVo queryById(Long appId) {
        return baseMapper.selectVoById(appId);
    }

    @Override
    public PayApp selectById(Long appId) {
        return baseMapper.selectById(appId);
    }

    /**
     * 分页查询应用列表列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 应用列表分页列表
     */
    @Override
    public <C> TableDataInfo<C> queryPageList(PayAppBo bo, PageQuery pageQuery, Class<C> voClass) {
        MPJLambdaWrapper<PayApp> lqw = buildQueryWrapper(bo);
        Page<C> result = baseMapper.selectJoinPage(pageQuery.build(), voClass, lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的应用列表列表
     *
     * @param bo 查询条件
     * @return 应用列表列表
     */
    @Override
    public <C> List<C> queryList(PayAppBo bo, Class<C> voClass) {
        MPJLambdaWrapper<PayApp> lqw = buildQueryWrapper(bo);
        return baseMapper.selectJoinList(voClass, lqw);
    }

    private MPJLambdaWrapper<PayApp> buildQueryWrapper(PayAppBo bo) {
        Map<String, Object> params = bo.getParams();
        MPJLambdaWrapper<PayApp> lqw = new MPJLambdaWrapper<>();
        lqw.leftJoin(PayGroup.class, PayGroup::getGroupId, PayApp::getGroupId);
        lqw.selectAll(PayApp.class).select(PayGroup::getGroupName);

        if (LoginHelper.isClient()) {
            lqw.eq(PayApp::getClientId, LoginHelper.getUserId());
        }
        else if (LoginHelper.isManager()) {
            lqw.eq(PayApp::getManagerId, LoginHelper.getUserId());
        }
        else if (LoginHelper.isAgent()) {
            lqw.eq(PayApp::getAgentId, LoginHelper.getUserId());
        }
        else if (!LoginHelper.isSuperAdmin()) {
            lqw.eq(PayApp::getAgentId, LoginHelper.getLoginUser().getAgentId());
        }

        lqw.like(StringUtils.isNotBlank(bo.getGroupName()), PayGroup::getGroupName, bo.getGroupName());
        lqw.eq(StringUtils.isNotBlank(bo.getAppSecret()), PayApp::getAppSecret, bo.getAppSecret());
        lqw.eq(StringUtils.isNotBlank(bo.getGateway()), PayApp::getGateway, bo.getGateway());
        lqw.eq(bo.getAppId() != null, PayApp::getAppId, bo.getAppId());
        lqw.eq(bo.getGoodsType() != null, PayApp::getGoodsType, bo.getGoodsType());
        lqw.eq(bo.getRatio() != null, PayApp::getRatio, bo.getRatio());
        lqw.eq(bo.getNeedMail() != null, PayApp::getNeedMail, bo.getNeedMail());
        lqw.eq(bo.getStatus() != null, PayApp::getStatus, bo.getStatus());
        lqw.eq(bo.getClientId() != null, PayApp::getClientId, bo.getClientId());
        lqw.eq(bo.getAgentId() != null, PayApp::getAgentId, bo.getAgentId());
        lqw.like(StringUtils.isNotBlank(bo.getRemark()), PayApp::getRemark, bo.getRemark());
        return lqw;
    }

    /**
     * 新增应用列表
     *
     * @param bo 应用列表
     * @return 是否新增成功
     */
    @Transactional
    @Override
    public R<Void> insertByBo(PayAppBo bo) {
        if (!LoginHelper.isSuperAdmin() && !LoginHelper.isAgent() && !LoginHelper.isManager()) {
            return R.fail("未授权");
        }
        if (bo.getClientId() == null) {
            return R.fail("请先选择商户");
        }

        SysUser client = sysUserMapper.selectById(bo.getClientId());
        if (client == null) {
            return R.fail("未找到所选商户，请重新选择");
        }

        if(bo.getGroupId() != null && LoginHelper.isManager()) {
            String groupIds = sysUserMapper.selectById(LoginHelper.getUserId()).getGroupIds();
            if(StringUtils.isBlank(groupIds) || Arrays.stream(groupIds.split(",")).noneMatch(id -> id.equals(String.valueOf(bo.getGroupId())))) {
                return R.fail("未找到所选轮询组，请重新选择");
            }
        }

        PayApp add = MapstructUtils.convert(bo, PayApp.class);
        if (add.getRefreshAutoUp() == null) {
            add.setRefreshAutoUp(0);
        }
        add.setClientName(client.getUserName());
        add.setAppSecret(UUID.randomUUID().toString().replaceAll("-", ""));
        add.setGateway(gatewayDomain);
        add.setIsDelete(0);
        add.setAgentId(client.getAgentId());
        add.setAgentName(client.getAgentName());
        add.setManagerId(client.getManagerId());
        add.setManagerName(client.getManagerName());
        add.setCreateTime(DateUtils.getNowDate());
        add.setUpdateTime(DateUtils.getNowDate());
        add.setSuccessTotal(BigDecimal.ZERO);
        if (add.getTotalLimit() == null) {
            add.setTotalLimit(BigDecimal.ZERO);
        }

        if (add.getTotalLimit() == null || add.getTotalLimit().compareTo(BigDecimal.ZERO) <= 0) {
            add.setTotalLimit(BigDecimal.ZERO);
            add.setRefreshTime("");
            add.setRefreshAutoUp(0);
        }

        baseMapper.insert(add);

        return R.ok();
    }

    /**
     * 修改应用列表
     *
     * @param bo        应用列表
     * @param dealGroup 是否处理轮询组
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(PayAppBo bo, Boolean dealGroup) {
        PayApp update = MapstructUtils.convert(bo, PayApp.class);

        PayApp old = baseMapper.selectById(bo.getAppId());
        if (old == null) {
            return false;
        }

        update.setUpdateId(LoginHelper.getUserId());
        update.setUpdateName(LoginHelper.getUsername());
        update.setUpdateTime(DateUtils.getNowDate());

        if (update.getTotalLimit() == null || update.getTotalLimit().compareTo(BigDecimal.ZERO) <= 0) {
            update.setTotalLimit(BigDecimal.ZERO);
            update.setRefreshTime("");
            update.setRefreshAutoUp(0);
        }

        if ((old.getTotalLimit() == null || old.getTotalLimit().compareTo(BigDecimal.ZERO) == 0) && update.getTotalLimit().compareTo(BigDecimal.ZERO) > 0) {
            update.setSuccessTotal(BigDecimal.ZERO);
        }

        if(bo.getGroupId() != null && LoginHelper.isManager()) {
            String groupIds = sysUserMapper.selectById(LoginHelper.getUserId()).getGroupIds();
            if(StringUtils.isBlank(groupIds) || Arrays.stream(groupIds.split(",")).noneMatch(id -> id.equals(String.valueOf(bo.getGroupId())))) {
                return false;
            }
        }

        boolean result = baseMapper.updateById(update) > 0;

        if (result && dealGroup) {
            if (bo.getGroupId() == null) {
                // 取消轮询组
                baseMapper.update(Wrappers.<PayApp>lambdaUpdate().eq(PayApp::getAppId, bo.getAppId()).set(PayApp::getGroupId, null));
            }
            if(bo.getPolicyId() == null) {
                baseMapper.update(Wrappers.<PayApp>lambdaUpdate().eq(PayApp::getAppId, bo.getAppId()).set(PayApp::getPolicyId, null));
            }
        }
        return result;
    }

    /**
     * 修改应用列表
     *
     * @param update 应用列表
     * @return 是否修改成功
     */
    @Override
    public Boolean updateById(PayApp update) {
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 校验并批量删除应用列表信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        LambdaQueryWrapper<PayApp> query = new LambdaQueryWrapper<>();
        query.in(PayApp::getAppId, ids);
        if (LoginHelper.isAgent()) {
            query.eq(PayApp::getAgentId, LoginHelper.getUserId());
        }
        if (LoginHelper.isClient()) {
            query.eq(PayApp::getClientId, LoginHelper.getUserId());
        }

        for (Long id : ids) {
            RedisUtils.deleteObject(OrderConstants.app_feign_key + id + ":successCount");
        }

        return baseMapper.delete(query) > 0;
    }

    /**
     * 刷新应用收款金额
     */
    @Override
    public void refreshAppMoney() {
        LocalDateTime time = LocalDateTime.now();
        int hour = time.getHour();
        int minute = time.getMinute();

        String minuteStr = minute < 30 ? "00" : "30";
        baseMapper.refreshAppMoney(String.format("%02d", hour) + ":" + minuteStr);
    }
}
